package com.sunchangming.stmdb;

import java.util.HashSet;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PessimisticTransaction implements Transaction {
	private final Set<Lockey> locks = new HashSet<Lockey>();
	private final static Logger logger = LoggerFactory.getLogger(PessimisticTransaction.class);

	private int trancount = 0;

	/* (non-Javadoc)
	 * @see com.tianshen.logic.concurrent.Transaction#add(com.tianshen.logic.concurrent.Lockey)
	 */
	@Override
	public void add(Lockey lockey) {
		if (!locks.contains(lockey)) {
			// 成功得到锁以后才加入容器。
			lockey.lock();
			locks.add(lockey);
		}
	}

	/* (non-Javadoc)
	 * @see com.tianshen.logic.concurrent.Transaction#begin()
	 */
	@Override
	public void begin() {
		++trancount;
	}

	/* (non-Javadoc)
	 * @see com.tianshen.logic.concurrent.Transaction#commit()
	 */
	@Override
	public void commit() {
		if (--trancount < 0)
			throw new XError("commit mismatch");
	}

	/* (non-Javadoc)
	 * @see com.tianshen.logic.concurrent.Transaction#rollback(int)
	 */
	@Override
	public void rollback(int savepoint) {
		if (--trancount < 0)
			throw new XError("rollback mismatch");
	}

	private static ThreadLocal<PessimisticTransaction> threadlocal = new ThreadLocal<PessimisticTransaction>();

	public static final PessimisticTransaction create() {
		PessimisticTransaction t = threadlocal.get();
		if (null == t)
			threadlocal.set(t = new PessimisticTransaction());
		return t;
	}

	public static final void destroy() {
		threadlocal.set(null);
	}

	public static final PessimisticTransaction current() {
		return threadlocal.get();
	}

	/* (non-Javadoc)
	 * @see com.tianshen.logic.concurrent.Transaction#perform(com.tianshen.logic.concurrent.AtomicClosure)
	 */
	@Override
	public <E> E perform(AtomicClosure<E> p) throws Throwable {
		E result = null;
		try {
			result = p.execute(this);
		} finally {
			this.finish();
		}
		return result;
	}

	/**
	 * 在结束的时候释放所有锁
	 */
	private void finish() {
		//unlock的顺序无所谓。
		for (final Lockey lockey : locks) {
			try {
				lockey.unlock();
			} catch (final Throwable e) {
				logger.error("unlock " + lockey, e);
			}
		}
		locks.clear();
	}

}
